import hashlib
from django.shortcuts import render, redirect
from app01 import models
from Utils.pagination import Pagination
from app01.forms import RegForm, ArticleForm, ArticleDetailForm, CategoryForm, SeriesForm
from django.db.models import Q, Sum, F
from django.http.response import JsonResponse
from django.utils import timezone


def login(request):
    """
    用于用户登录
    1.判断是否为POST请求
    2.获取用户输入的数据
    3.把获取的数据，在数据库中比较.first()：判断有值就返回成功，没有就返回None
    4.成功就重定向页面，没有成功就返回原登录页面
    """
    if request.method == "POST":
        # 获取用户输入的内容
        username = request.POST.get("username")
        password = request.POST.get("password")
        md5 = hashlib.md5()
        md5.update(password.encode("utf-8"))
        user_obj = models.User.objects.filter(username=username,
                                              password=md5.hexdigest()).first()  # first有就为True,没有返回为空
        if user_obj:
            # 登录成功
            # 保存登录状态
            request.session["is_login"] = True
            request.session["username"] = user_obj.username
            request.session["pk"] = user_obj.pk
            url = request.GET.get("url")
            if url:  # 为None的什么就返回index页面登录成功
                return redirect(url)
            return redirect("index")
        error = "用户名或密码错误"
    return render(request, "login.html", locals())


def logout(request):
    request.session.delete()
    return redirect("index")


# 注册
def register(request):
    """
    用于注册
    我们这里是直接使用了数据库中的字段，来写这个form表单的数据
    models.User  获取整个User表中的字段
    fields = ["username","password"]  获取自定义的models的字段
    fields = "__all__"  获取所有的字段
    labels = {  # 给选中的字段重命名
        "username":"用户名",
    }
    widgets = {  # 改对应字段的input框的格式
        'password': forms.PasswordInput
    }
    error_messages = {  # 修改每个字段默认的报错信息
        "username": {
            "required": "必填项"
        }
    }
    cleaned_data.get("phone")  # 获取phone字段，用户输入的内容
    self._validate_unique = True  # 数据库校验唯一
    self.cleaned_data  # 就返回全部的数据
    self.add_error("re_pwd", "两次密码不一致！！")  # 给对应的字段后面添加错误信息

    1.获取form表单的数据
    2.如果有数据的话，返回注册成功，并保存在数据库中去
    3.重定向到登录页面

    保存在数据库
    方法一:
    form_obj.cleaned_data.pop("re_pwd")  删除字段为re_pwd的
    models.User.objects.create(**form_obj.cleaned_data)  将所有的数据提交到数据库
    方法二
    如果继承了forms.ModelForm就直接使用：form_obj.save()
    """
    form_obj = RegForm()  # 获取一个空的form
    if request.method == "POST":
        form_obj = RegForm(request.POST, request.FILES)  # 获取的一个有数据的form

        if form_obj.is_valid():
            # 注册成功
            form_obj.save()  # 因为继承了ModelForm,所有可以直接保存
            return redirect("login")

    return render(request, "register.html", {"form_obj": form_obj})


def index(request):
    # 查询所有的文章
    all_article = models.Article.objects.filter(publish_status=True).order_by("-create_time")
    page = Pagination(request, all_article.count(), 5)
    return render(request, "index.html", {"all_article": all_article[page.start:page.end], "page_html": page.page_html})


def article(request, pk):
    article_obj = models.Article.objects.get(pk=pk)
    return render(request, "article.html", {"article_obj": article_obj})


def backend(request):
    return render(request, "dsaboard.html")


# 模糊查询
def get_query(request, filed_list):
    # 传入一个列表['title','detail_content']
    query = request.GET.get("query", '')
    q = Q()
    # Q(title__contains=query) | Q(detail__content__contains=query) | Q(create_time__contains=query)
    q.connector = "OR"
    # q.children.append(Q(title__contains=query))
    # q.children.append(Q(detail__content__contains=query))

    # Q(title__contains=query) 可以写成 Q("title__contains",query)
    for field in filed_list:
        q.children.append(Q(("{}__contains".format(field), query)))

    return q


"""
文章的展示 
"""


def article_list(request):
    q = get_query(request, ["title", "detail__content"])
    all_articles = models.Article.objects.filter(q, author=request.user_obj)  # 改成当前作者的所有文章
    page = Pagination(request, all_articles.count(), 5)
    return render(request, "article_list.html",
                  {"all_articles": all_articles[page.start:page.end], "page_html": page.page_html})


# 新增文章
def article_add(request):
    # obj = models.Article.objects.filter(author=request.user_obj)
    form_obj = ArticleForm(request)
    article_detail_form_obj = ArticleDetailForm()
    if request.method == "POST":
        form_obj = ArticleForm(request, request.POST)
        article_detail_form_obj = ArticleDetailForm(request.POST)

        if form_obj.is_valid() and article_detail_form_obj.is_valid():
            # 插入文章详情 因为我们在用modelform的时候去掉了detail
            # detail = request.POST.get("detail")  # 获取用户输入的内容
            # 创建文章详情的对象
            # detail_obj = models.ArticleDetail.objects.create(content=detail)  # 把用户输入的内容插入到文章详情数据库
            # 插入文章
            detail_obj = article_detail_form_obj.save()  # 分开保存
            form_obj.cleaned_data["detail_id"] = detail_obj.pk  # 因为我们开始去掉了detail，所以我们用字典新增一个detail_id
            models.Article.objects.create(**form_obj.cleaned_data)  # 把字典中的值分断插入数据库中
            url = request.GET.get("url")
            if url:
                return redirect(url)
            return redirect("article_list")
    return render(request, "article_add.html",
                  {"form_obj": form_obj, "article_detail_form_obj": article_detail_form_obj})


# 编辑文章
def article_edit(request, pk):
    """
    form_obj：是获取的所有的input框
    instance=obj：要编辑的对象
        1.先通过id的形式查找有没有数据
        2.有数据的话通过instance创建一个form
        3.如果是POST请求，就获取用户的数据创建一个有数据的form
        4.判断里面有没有数据，
        5.有数据，就获取文章的内容通过form_obj.instance.把数据给content,保存数据
        6.没有就返回原页面
    """
    # 因为我们用的是modelform，所以用下面的简单点
    obj = models.Article.objects.filter(pk=pk).first()  # 获取文章表中有没有id
    form_obj = ArticleForm(request, instance=obj)  # 创建一个空的form,通过instance创建新对象，
    article_detail_form_obj = ArticleDetailForm(instance=obj.detail)
    if request.method == "POST":
        form_obj = ArticleForm(request, request.POST, instance=obj)  # 把request.POST获取的值，给form
        article_detail_form_obj = ArticleDetailForm(request.POST, instance=obj.detail)
        if form_obj.is_valid() and article_detail_form_obj.is_valid():
            # form_obj.instance.detail.content = request.POST.get("detail")  # 获取用户输入的内容，把内容传递给instance创建对象的content
            # form_obj.instance.detail.save()  # 保存文章详情
            article_detail_form_obj.save()
            form_obj.save()  # 保存文章的信息
            url = request.GET.get("url")
            if url:
                return redirect(url)
            return redirect("article_list")
    return render(request, "article_edit.html",
                  {"form_obj": form_obj, "article_detail_form_obj": article_detail_form_obj})


# 删除文章
def article_del(request, pk):
    models.Article.objects.filter(pk=pk).delete()
    return redirect("/article_list/")


users = [{"name": "alex--{}".format(i)} for i in range(500)]


def user_list(request):
    page = Pagination(request, len(users), 5)
    return render(request, "user_list.html", {"users": users[page.start:page.end], "page_html": page.page_html})


# 文章的分类
# 展示
def category_list(request):
    q = get_query(request, ["title", "pk"])
    category_lists = models.Category.objects.filter(q)
    return render(request, "category_list.html", {"category_lists": category_lists})


def category_change(request, pk=None):
    obj = models.Category.objects.filter(pk=pk).first()
    form_obj = CategoryForm(instance=obj)
    if request.method == "POST":
        form_obj = CategoryForm(request.POST, instance=obj)
        if form_obj.is_valid():
            form_obj.save()
            # 编辑后跳转原页面
            url = request.GET.get("url")
            if url:
                return redirect(url)
            return redirect("category_list")
    titles = "编辑" if pk else "新增分类"
    return render(request, "form.html", {"form_obj": form_obj, "titles": titles})


# 删除分类
def category_del(request, pk):
    models.Category.objects.filter(pk=pk).delete()
    return redirect("/category_list/")


# 评论
def comment(request):
    obj = models.Comment.objects.create(
        **request.GET.dict())  # <QueryDict: {'content': ['你好'], 'article_id': ['5'], 'author_id': ['1']}>
    return JsonResponse({'status': True, "time": timezone.localtime(obj.time).strftime("%Y-%m-%d %H:%M:%S")})


# 系列的管理
def series_list(request):
    q = get_query(request, [])
    series_all = models.Series.objects.filter(q)
    return render(request, "series_list.html", {"series_all": series_all})


# 编辑和添加
def series_change(request, pk=None):
    obj = models.Series.objects.filter(pk=pk).first()
    form_obj = SeriesForm(instance=obj)
    if request.method == "POST":
        form_obj = SeriesForm(request.POST, instance=obj)
        if form_obj.is_valid():
            # form_obj.save()
            # 新增了系列的对象
            form_obj.instance.save()
            obj = form_obj.instance
            # 保存的系列和文章的多对多关系
            obj.articles.set(form_obj.cleaned_data.get("articles"))  # [id] [对象]
            # 保存的系列和用户的多对多关系
            users = form_obj.cleaned_data.get("users")
            # 新添加用户
            old = set(obj.users.all())
            new = set(users)
            add_users = new - old
            if add_users:
                obj_list = []
                for user in form_obj.cleaned_data.get('users'):
                    obj_list.append(models.UserSeries(user_id=user.pk, series_id=obj.pk))
                if obj_list:
                    models.UserSeries.objects.bulk_create(obj_list)  # 批量插入
            # 删除用户
            del_users = old - new
            if del_users:
                models.UserSeries.objects.filter(series=obj.pk, user_id__in=del_users).delete()

            return redirect("series_list")
    titles = "编辑系列" if pk else "新增系列"
    return render(request, "form.html", {"form_obj": form_obj, "titles": titles})


# 系列删除
def series_del(request, pk):
    models.Series.objects.filter(pk=pk).delete()
    return redirect("/series_list/")


def profile(request):
    all_user_series = models.UserSeries.objects.filter(user=request.user_obj)
    return render(request, "profile.html", {"all_user_series": all_user_series})


def point(request):
    # 插入得分记录
    obj, created = models.PointDetail.objects.get_or_create(**request.GET.dict())
    if created:
        # 更新系列的进度
        query_set = models.UserSeries.objects.filter(user=request.user_obj, series__in=obj.article.series_set.all())
        # 加积分前计算每个系列的总积分
        ret = query_set.values("series_id").annotate(total_points=Sum("series__articles__point"))
        for i in ret:
            models.UserSeries.objects.filter(user=request.user_obj, series_id=i["series_id"]).update(
                total_points=i["total_points"])
        # 加积分
        query_set.update(points=F("points") + obj.point, progress=F("points") / F("total_points") * 100)
        return JsonResponse({"status": True})
    return JsonResponse({"status": False})
